
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/epoll.h>
#define USE_BSD
#include <sys/time.h>
#include <sys/resource.h>

static volatile int cnt = 0;

void count(int signo)
{
	printf("%d\n", cnt);
	cnt = 0;
	alarm(1);
}

void die(const char *msg)
{
	perror(msg);
	exit(EXIT_FAILURE);
}

#define safe_exec(func, args...) \
	({ \
	 	int retval; \
	 	\
		if ((retval = func(args)) < 0) \
			die(#func); \
	 	retval; \
	})

#define safe_epoll_create(nr) safe_exec(epoll_create, nr)
#define safe_epoll_ctl(epfd, cmd, fd, event) \
		safe_exec(epoll_ctl, epfd, cmd, fd, event)

int main(int argc, char *argv[])
{
	int fd, max_fd, i;
	struct timeval tv, tv_old, tv_inter;
	struct rlimit rlim;
	struct epoll_event ev = {
		.events = EPOLLIN,
		.data.u32 = 1
	};

	if (argc < 3) {
		printf("Usage: %s max_fd default_nr [inc|dec]\n", argv[0]);
		return EXIT_FAILURE;
	}
	
	rlim.rlim_cur = atoi(argv[1]);
	rlim.rlim_max = atoi(argv[1]);
	setrlimit(RLIMIT_NOFILE, &rlim);

	fd = safe_epoll_create(atoi(argv[2]));

	while ((i = dup(1)) != -1)
		max_fd = i;
	printf("max_fd = %d\n", max_fd);

	gettimeofday(&tv_old, NULL);
	if (argc > 3 && strcmp(argv[3], "dec") == 0) {
		for (i = max_fd; i >= 0; i --) {
			if (i == fd)
				continue;
			safe_epoll_ctl(fd, EPOLL_CTL_ADD, i, &ev);
		}
	} else {
		for (i = 0; i <= max_fd; i ++) {
			if (i == fd)
				continue;
			safe_epoll_ctl(fd, EPOLL_CTL_ADD, i, &ev);
		}
	}
	gettimeofday(&tv, NULL);
	timersub(&tv, &tv_old, &tv_inter);
	printf("warming time: %d.%06ds\n", tv_inter.tv_sec,
			tv_inter.tv_usec);

	signal(SIGALRM, count);
	alarm(1);
	max_fd ++;
	for (i = 0; 1; i = (i + 1) % max_fd) {
		if (i == fd)
			continue;
		safe_epoll_ctl(fd, EPOLL_CTL_DEL, i, &ev);
		safe_epoll_ctl(fd, EPOLL_CTL_ADD, i, &ev);
		cnt ++;
	}

	return 0;
}
